package shake.el;

import java.util.Map;

import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.el.VariableMapper;

import shake.util.Clousre;

import com.google.inject.Inject;
import com.google.inject.Singleton;

@Singleton
public class ELs {
	@Inject
	ELVariable variable;

	@Inject
	ExpressionFactory expressionFactory;

	@Inject
	ELResolver resolver;

	@Inject
	FunctionMapper functionMapper;

	@Inject
	VariableMapper variableMapper;

	public ELContext createELContext() {
		return new ELContext() {

			@Override
			public ELResolver getELResolver() {
				return resolver;
			}

			@Override
			public FunctionMapper getFunctionMapper() {
				return functionMapper;
			}

			@Override
			public VariableMapper getVariableMapper() {
				return variableMapper;
			}
		};
	}

	public ValueExpression createValueExpression(String el) {
		return expressionFactory.createValueExpression(createELContext(), el,
				Object.class);
	}

	public MethodExpression createMethodExpression(String el) {
		return expressionFactory.createMethodExpression(createELContext(), el,
				Object.class, new Class[] {});
	}

	public ExpressionFactory getExpressionFactory() {
		return expressionFactory;
	}

	public void eval(String name, Object obj, Clousre clousre) {
		Object replaced = variable.put(name, obj);
		try {
			clousre.invoke();
		} finally {
			variable.put(name, replaced);
		}
	}

	public void eval(Map<String, Object> bindParam, Clousre clousre) {
		try {
			variable.push(bindParam);
			clousre.invoke();
		} finally {
			variable.pop();
		}
	}

	public MethodExpression createMethodExpression(ELContext elContext,
			String expression, Class expectedType, Class[] params) {
		return expressionFactory.createMethodExpression(elContext, expression,
				expectedType, params);
	}

	public ValueExpression createValueExpression(ELContext context,
			String expression, Class<?> expectedType) {
		return expressionFactory.createValueExpression(context, expression,
				expectedType);
	};

	public ValueExpression createValueExpression(Object instance,
			Class<?> expectedType) {
		return expressionFactory.createValueExpression(instance, expectedType);
	}
}
